package com.self.engine.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.self.common.enums.OrderDirection;
import com.self.common.param.ExchangeTrade;
import com.self.common.param.Order;
import com.self.engine.mapper.EntrustOrderMapper;
import com.self.engine.model.EntrustOrder;
import com.self.engine.model.Market;
import com.self.engine.model.TurnoverOrder;
import com.self.engine.param.OrderParam;
import com.self.engine.rocketmq.OrderProducer;
import com.self.engine.service.EntrustOrderService;
import com.self.engine.service.MarketService;
import com.self.engine.service.TurnoverOrderService;
import com.self.finance.feign.AccountServiceFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;

@Slf4j
@Service
public class EntrustOrderServiceImpl extends ServiceImpl<EntrustOrderMapper, EntrustOrder> implements EntrustOrderService{


    @Autowired
    private MarketService marketService;

    @Autowired
    private AccountServiceFeign accountServiceFeign;

    @Autowired
    private OrderProducer orderProducer;

    @Autowired
    private TurnoverOrderService turnoverOrderService;

    /**
     * 创建一个新的委托大
     *
     * @param userId     用户的id
     * @param orderParam 委托单的数据
     * @return
     */
    @Transactional
    @Override
    public Boolean createEntrustOrder(Long userId, OrderParam orderParam) {
        // 1 层层校验
        String symbol = orderParam.getSymbol();
        Market markerBySymbol = marketService.getMarkerBySymbol(symbol);
        if (markerBySymbol == null) {
            throw new IllegalArgumentException("您购买的交易对不存在");
        }

        BigDecimal price = orderParam.getPrice().setScale(markerBySymbol.getPriceScale(), RoundingMode.HALF_UP);
        BigDecimal volume = orderParam.getVolume().setScale(markerBySymbol.getNumScale(), RoundingMode.HALF_UP);

        // 计算成交额度
        BigDecimal mum = price.multiply(volume);

        // 交易数量的交易
        BigDecimal numMax = markerBySymbol.getNumMax();
        BigDecimal numMin = markerBySymbol.getNumMin();
        if (volume.compareTo(numMax) > 0 || volume.compareTo(numMin) < 0) {
            throw new IllegalArgumentException("交易的数量不在范围内");
        }

        // 校验交易额
        BigDecimal tradeMin = markerBySymbol.getTradeMin();
        BigDecimal tradeMax = markerBySymbol.getTradeMax();

        if (mum.compareTo(tradeMin) < 0 || mum.compareTo(tradeMax) > 0) {
            throw new IllegalArgumentException("交易的额度不在范围内");
        }
        // 计算手续费
        BigDecimal fee = BigDecimal.ZERO;
        BigDecimal feeRate = BigDecimal.ZERO;
        Integer type = orderParam.getType();
        if (type == 1) { // 买入 buy
            feeRate = markerBySymbol.getFeeBuy();
            fee = mum.multiply(markerBySymbol.getFeeBuy());
        } else { // 卖出 sell
            feeRate = markerBySymbol.getFeeSell();
            fee = mum.multiply(markerBySymbol.getFeeSell());
        }
        EntrustOrder entrustOrder = new EntrustOrder();
        entrustOrder.setUserId(userId);
        entrustOrder.setAmount(mum);
        entrustOrder.setType(orderParam.getType().byteValue());
        entrustOrder.setPrice(price);
        entrustOrder.setVolume(volume);
        entrustOrder.setFee(fee);
        entrustOrder.setCreated(new Date());
        entrustOrder.setStatus((byte) 0);
        entrustOrder.setMarketId(markerBySymbol.getId());
        entrustOrder.setMarketName(markerBySymbol.getName());
        entrustOrder.setMarketType(markerBySymbol.getType());
        entrustOrder.setSymbol(markerBySymbol.getSymbol());
        entrustOrder.setFeeRate(feeRate);
        entrustOrder.setDeal(BigDecimal.ZERO);
        entrustOrder.setFreeze(entrustOrder.getAmount().add(entrustOrder.getFee())); // 冻结余额

        boolean save = save(entrustOrder);
        if (save) {
            // 用户余额的扣减
            Long coinId = null;
            if (type == 1) { // 购买操作
                coinId = markerBySymbol.getBuyCoinId();

            } else {
                coinId = markerBySymbol.getSellCoinId();
            }
            if (entrustOrder.getType() == (byte) 1) {
                accountServiceFeign.lockUserAmount(userId, coinId, entrustOrder.getFreeze(), "trade_create", entrustOrder.getId(), fee);
            }
            // 发送到撮合系统里面
            Message<Order> message = MessageBuilder.withPayload(entrustOrderConvertOrder(entrustOrder))
                    .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE)
                    .build();
            orderProducer.outputMessage().send(message);
        }
        return save;
    }

    private Order entrustOrderConvertOrder(EntrustOrder entrustOrder) {
        Order order = new Order();
        // 设置交易对
        order.setSymbol(entrustOrder.getSymbol());
        // 设置交易额
        order.setAmount(entrustOrder.getVolume().add(entrustOrder.getDeal().negate()));
        // 设置交易价格
        order.setPrice(entrustOrder.getPrice());
        // 设置交易时间
        order.setTime(entrustOrder.getCreated().getTime());
        // 设置交易的id
        order.setOrderId(entrustOrder.getId().toString());
        // 设置交易的方向
        order.setOrderDirection(OrderDirection.getOrderDirection(entrustOrder.getType().intValue()));
        return order;
    }

    @Transactional
    @Override
    public void writeExchangeTrade(ExchangeTrade exchangeTrade) {
        String sellOrderId = exchangeTrade.getSellOrderId();
        String buyOrderId = exchangeTrade.getBuyOrderId();
        EntrustOrder sellOrder = getById(sellOrderId);
        EntrustOrder buyOrder = getById(buyOrderId);
        Long marketId = sellOrder.getMarketId();
        Market market = marketService.getById(marketId);
        // 1 新增成交记录
        addTurnOverOrderRecord(sellOrder, buyOrder, market, exchangeTrade);
        // 2 更新委托单
        updateEntrustOrder(sellOrder, buyOrder, exchangeTrade);
        //TODO: 3 余额的返还
        backAccount(sellOrder, buyOrder, exchangeTrade, market);
    }

    private void backAccount(EntrustOrder sellOrder, EntrustOrder buyOrder, ExchangeTrade exchangeTrade, Market market) {

    }

    private void updateEntrustOrder(EntrustOrder sellOrder, EntrustOrder buyOrder, ExchangeTrade exchangeTrade) {
        //成交额
        sellOrder.setDeal(exchangeTrade.getAmount());
        buyOrder.setDeal(exchangeTrade.getAmount());

        BigDecimal volume = sellOrder.getVolume();
        if (exchangeTrade.getAmount().compareTo(volume) == 0){
            sellOrder.setStatus((byte) 1);
        }
        BigDecimal buyOrderVolume = buyOrder.getVolume();
        if (exchangeTrade.getAmount().compareTo(buyOrderVolume) == 0) {
            // 状态(已经完成)
            buyOrder.setStatus((byte) 1);
        }

        // 更新委托单
        updateById(sellOrder);
        updateById(buyOrder);

    }

    private void addTurnOverOrderRecord(EntrustOrder sellOrder, EntrustOrder buyOrder, Market market, ExchangeTrade exchangeTrade) {

        // 出售订单的成交记录
        TurnoverOrder sellTurnoverOrder = new TurnoverOrder();
        sellTurnoverOrder.setSellOrderId(sellOrder.getId());
        sellTurnoverOrder.setBuyCoinId(buyOrder.getId());
        sellTurnoverOrder.setBuyVolume(exchangeTrade.getAmount());
        sellTurnoverOrder.setAmount(exchangeTrade.getSellTurnover());

        sellTurnoverOrder.setBuyCoinId(market.getBuyCoinId());
        sellTurnoverOrder.setSellCoinId(market.getSellCoinId());
        sellTurnoverOrder.setCreated(new Date());
        sellTurnoverOrder.setBuyUserId(buyOrder.getUserId());
        sellTurnoverOrder.setSellUserId(sellOrder.getUserId());
        sellTurnoverOrder.setPrice(exchangeTrade.getPrice());
        sellTurnoverOrder.setBuyPrice(buyOrder.getPrice());
        sellTurnoverOrder.setTradeType((byte)2);
        turnoverOrderService.save(sellTurnoverOrder);

        // 买方数据的成交记录
        TurnoverOrder buyTurnoverOrder = new TurnoverOrder();
        buyTurnoverOrder.setBuyOrderId(buyOrder.getId());
        buyTurnoverOrder.setSellOrderId(sellOrder.getId());
        buyTurnoverOrder.setAmount(exchangeTrade.getBuyTurnover());
        buyTurnoverOrder.setBuyVolume(exchangeTrade.getAmount());
        buyTurnoverOrder.setSellUserId(sellOrder.getUserId());
        buyTurnoverOrder.setBuyUserId(buyOrder.getUserId());
        buyTurnoverOrder.setSellCoinId(market.getSellCoinId());
        buyTurnoverOrder.setBuyCoinId(market.getBuyCoinId());
        buyTurnoverOrder.setCreated(new Date());
        sellTurnoverOrder.setTradeType((byte)1);
        turnoverOrderService.save(sellTurnoverOrder);
    }

    @Override
    public void cancleEntrustOrderToDb(String orderId) {
        // 2 数据库的操作
        if (StringUtils.hasText(orderId)) {
            Long orderIdVal = Long.valueOf(orderId);
            EntrustOrder entrustOrder = getById(orderIdVal);
            if (entrustOrder != null){
                entrustOrder.setStatus((byte) 2);
                updateById(entrustOrder);
            }
        }
    }

    @Override
    public void cancleEntrustOrder(Long orderId) {
        // 取消委托单
        // 1 将该委托单从撮合引擎里面的委托单账本里面移除
        EntrustOrder entrustOrder = getById(orderId);
        Assert.notNull(entrustOrder,"委托单不存在");
        Order order = new Order();
        order.setOrderId(orderId.toString());
        order.setOrderStatus(2);
        order.setPrice(entrustOrder.getPrice());
        Message<Order> message = MessageBuilder.withPayload(order).setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON).build();
        orderProducer.cancleOrderOutMessage().send(message);
    }
}
